package com.sailing.xjpb.web.base.configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sailing.xjpb.web.base.api.ApiVersionRequestMappingHandlerMapping;
import com.sailing.xjpb.web.base.converter.JacksonHttpMessageConverter;
import com.sailing.xjpb.web.base.converter.PageableMethodArgumentResolver;
import com.sailing.xjpb.web.base.converter.StringToDateConverter;
import com.sailing.xjpb.web.base.valid.ServiceParameterValidAspect;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.resource.ResourceResolver;
import org.springframework.web.servlet.resource.ResourceResolverChain;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Validator;
import java.util.List;

/**
 * WebMvc相关配置
 *
 * @author YaoWei
 */
@Slf4j
@Configuration
public class SailingWebMvcConfigurerAdapter implements WebMvcConfigurer, WebMvcRegistrations {

    @Autowired
    private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;

    @Autowired
    private SailingWebMvcConfigurer sailingWebMvcConfigurer;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new PageableMethodArgumentResolver());
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToDateConverter());
        sailingWebMvcConfigurer.addFormatters(registry);
    }

    @Override
    public void addInterceptors(@NonNull InterceptorRegistry registry) {
        sailingWebMvcConfigurer.addInterceptors(registry);
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(mappingJackson2HttpMessageConverter);
    }

    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new ApiVersionRequestMappingHandlerMapping();
    }

    @Bean
    @Primary
    public MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter(ObjectMapper objectMapper) {
        return new JacksonHttpMessageConverter(objectMapper);
    }

    @Bean
    @ConditionalOnMissingBean(SailingWebMvcConfigurer.class)
    public SailingWebMvcConfigurer sailingWebMvcConfigurer() {
        return new SailingWebMvcConfigurer() {
        };
    }

    @Bean
    public BeforeRequestBodyHandlerMethodArgumentResolverConfigure beforeRequestBodyHandlerMethodArgumentResolverConfigure() {
        return new BeforeRequestBodyHandlerMethodArgumentResolverConfigure();
    }

    /**
     * add by YaoWei since 2024-06-26 service层参数校验
     *
     * @return 参数校验切面
     */
    @Bean
    public ServiceParameterValidAspect serviceParameterValidAspect(Validator validator) {
        return new ServiceParameterValidAspect(validator);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //此处是要找到我们在项目中用到静态资源引入的地方增加过滤拦截【重要事情说三遍】【重要事情说三遍】【重要事情说三遍】
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/").resourceChain(true)
                .addResolver(new PathPatternResourceResolver());
        log.info("【高危】【CVE-2024-38816】Spring Framework 特定条件下目录遍历漏洞---临时修复--new PathPatternResourceResolver()");
        // 应用自行扩展
        sailingWebMvcConfigurer.addResourceHandlers(registry);
    }

    /**
     * <a href="https://wiki.sit.com.cn/pages/viewpage.action?pageId=83531210">【高危】【CVE-2024-38816】Spring Framework 特定条件下目录遍历漏洞---临时修复</a>
     */
    private static class PathPatternResourceResolver implements ResourceResolver {

        @Override
        public Resource resolveResource(HttpServletRequest request, @NonNull String requestPath
                , @NonNull List<? extends Resource> locations, ResourceResolverChain chain) {
            return chain.resolveResource(request, requestPath, locations);
        }

        @Override
        public String resolveUrlPath(@NonNull String resourcePath, @NonNull List<? extends Resource> locations
                , ResourceResolverChain chain) {
            return chain.resolveUrlPath(resourcePath, locations);
        }
    }
}